//
//  CoreDataManager.m
//  alotOf
//
//  Created by Mac_Black_Mini on 2025/9/4.
//

#import "CoreDataManager.h"

NS_ASSUME_NONNULL_BEGIN

@implementation CoreDataManager

static CoreDataManager *instance;
+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if(!instance){
            instance = [[super allocWithZone:NULL] init];
            
           
        }
    });
    return instance;
}



+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

+ (id)alloc {
    return [self allocWithZone:NULL];
}


- (NSManagedObjectContext *)managedObjectContext{

    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    //实例化
    //ConcurrencyType:并发(性)
    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

    //指定上下文所属的存储调度器
    _managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator;

    return _managedObjectContext;
}



- (NSManagedObjectModel *)managedObjectModel{


    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }

    //获取模型描述文件URL, .xcdatamodeld文件编译后在bundle里生成.momd文件
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"NodeModel" withExtension:@"momd"];

    //实例化 -  指定模型描述文件
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];


    return _managedObjectModel;

}


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{

    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    //实例化 - 指定管理对象模型
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];

    //添加存储器
    //Type:存储类型, 数据库/XML/二进制/内存
    //configuration:不需要额外配置,可以为nil
    //URL:数据保存的文件的URL 这里我们放到documents里
    //options:可以为空

    // 构建SQLite数据库文件的路径
     NSURL *storeUrl = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"node.sqlite"];
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    NSError *error;
    NSPersistentStore *store =  [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:nil];
    if (store == nil) {
            // Report any error we got.
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
            dict[NSLocalizedFailureReasonErrorKey] = failureReason;
            dict[NSUnderlyingErrorKey] = error;
            error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
            // Replace this with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }

    return _persistentStoreCoordinator;
}


/// 保存上下文（带错误传出）
/// @param error 错误信息（传出参数，保存失败时赋值）
/// @return 成功返回 YES，失败返回 NO
- (BOOL)saveContextWithError:(NSError **)error {
    NSManagedObjectContext *context = self.managedObjectContext;
    if (!context) {
        if (error) {
            *error = [NSError errorWithDomain:@"con.rabbitV.com.CoreDataError"
                                        code:1000
                                    userInfo:@{NSLocalizedDescriptionKey:@"ManagedObjectContext 未初始化"}];
        }
        return NO;
    }
    
    // 无变更时直接返回成功，避免无效保存
    if (!context.hasChanges) return YES;
    
    // 执行保存并返回结果
    BOOL saveSuccess = [context save:error];
    if (!saveSuccess) {
        NSLog(@"❌ CoreData 保存失败：%@", (*error).localizedDescription);
    }
    return saveSuccess;
}

// 保留原无参保存方法（兼容旧代码）
- (void)saveContext {
    NSError *error;
    [self saveContextWithError:&error];
    if (error) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort(); // 开发阶段保留，生产环境建议替换为友好处理
    }
}
/// CoreData 查询方法
/// @param entityName 实体名（需与 .xcdatamodeld 中定义的一致）
/// @param predicate 过滤条件（如“id == 123”，nil 表示查询所有）
/// @param sortDescriptors 排序规则（nil 表示不排序）
/// @param limit 分页数量（nil 表示无限制）
/// @param offset 分页偏移量（nil 表示从第0条开始）
/// @param error 错误信息（传出参数，查询失败时赋值）
/// @return 符合条件的 NSManagedObject 数组（失败返回 nil）
- (nullable NSArray<NSManagedObject *> *)queryDataWithEntityName:(NSString *)entityName
                                                       predicate:(nullable NSPredicate *)predicate
                                               sortDescriptors:(nullable NSArray<NSSortDescriptor *> *)sortDescriptors
                                                         limit:(nullable NSNumber *)limit
                                                        offset:(nullable NSNumber *)offset
                                                          error:(NSError **)error {
    // 1. 校验必要参数
    if (entityName.length == 0) {
        if (error) {
            *error = [NSError errorWithDomain:@"con.rabbitV.com.CoreDataError"
                                        code:1001
                                    userInfo:@{NSLocalizedDescriptionKey:@"实体名不能为空"}];
        }
        return nil;
    }
    
    // 2. 创建查询请求
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];
    // 设置过滤条件
    fetchRequest.predicate = predicate;
    // 设置排序规则
    fetchRequest.sortDescriptors = sortDescriptors;
    // 设置分页（可选）
    if (limit) fetchRequest.fetchLimit = limit.integerValue;
    if (offset) fetchRequest.fetchOffset = offset.integerValue;
    
    // 3. 执行查询
    NSError *fetchError = nil;
    NSArray<NSManagedObject *> *result = [self.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError];
    if (fetchError) {
        if (error) *error = fetchError;
        NSLog(@"❌ CoreData 查询失败：%@", fetchError.localizedDescription);
        return nil;
    }
    
    return result;
}
/// CoreData 修改方法
/// @param entityName 实体名
/// @param predicate 过滤条件（nil 表示修改所有该实体对象）
/// @param modifyBlock 修改逻辑（传入找到的对象，在 block 中设置属性）
/// @param error 错误信息（传出参数，修改失败时赋值）
/// @return 成功返回 YES，失败返回 NO
- (BOOL)modifyDataWithEntityName:(NSString *)entityName
                       predicate:(nullable NSPredicate *)predicate
                     modifyBlock:(void(^)(NSManagedObject *object))modifyBlock
                           error:(NSError **)error {
    // 1. 校验参数
    if (entityName.length == 0 || !modifyBlock) {
        if (error) {
            *error = [NSError errorWithDomain:@"con.rabbitV.com.CoreDataError"
                                        code:1002
                                    userInfo:@{NSLocalizedDescriptionKey:@"实体名不能为空或修改block未传"}];
        }
        return NO;
    }
    
    // 2. 先查询符合条件的对象
    NSArray<NSManagedObject *> *targetObjects = [self queryDataWithEntityName:entityName
                                                                    predicate:predicate
                                                            sortDescriptors:nil
                                                                      limit:nil
                                                                     offset:nil
                                                                       error:error];
    if (!targetObjects || targetObjects.count == 0) {
        if (error) {
            *error = [NSError errorWithDomain:@"con.rabbitV.com.CoreDataError"
                                        code:1003
                                    userInfo:@{NSLocalizedDescriptionKey:@"未找到需修改的对象"}];
        }
        return NO;
    }
    
    // 3. 执行修改逻辑
    for (NSManagedObject *object in targetObjects) {
        modifyBlock(object); // 传入对象，由外部设置属性（如 object.name = @"新名称"）
    }
    
    // 4. 保存修改
    return [self saveContextWithError:error];;
}
/// CoreData 删除方法
/// @param entityName 实体名
/// @param predicate 过滤条件（nil 表示删除该实体所有对象，谨慎使用！）
/// @param error 错误信息（传出参数，删除失败时赋值）
/// @return 成功返回 YES，失败返回 NO
- (BOOL)deleteDataWithEntityName:(NSString *)entityName
                       predicate:(nullable NSPredicate *)predicate
                           error:(NSError **)error {
    // 1. 校验必要参数
    if (entityName.length == 0) {
        if (error) {
            *error = [NSError errorWithDomain:@"con.rabbitV.com.CoreDataError"
                                        code:1004
                                    userInfo:@{NSLocalizedDescriptionKey:@"实体名不能为空"}];
        }
        return NO;
    }
    
    // 2. 查询需删除的对象
    NSArray<NSManagedObject *> *targetObjects = [self queryDataWithEntityName:entityName
                                                                    predicate:predicate
                                                            sortDescriptors:nil
                                                                      limit:nil
                                                                     offset:nil
                                                                       error:error];
    if (!targetObjects || targetObjects.count == 0) {
        if (error) {
            *error = [NSError errorWithDomain:@"con.rabbitV.com.CoreDataError"
                                        code:1005
                                    userInfo:@{NSLocalizedDescriptionKey:@"未找到需删除的对象"}];
        }
        return NO;
    }
    
    // 3. 批量删除
    NSManagedObjectContext *context = self.managedObjectContext;
    for (NSManagedObject *object in targetObjects) {
        [context deleteObject:object];
    }
    
    // 4. 保存删除操作
    return [self saveContextWithError:error];
}

@end

NS_ASSUME_NONNULL_END
